<?php
/**
 * 获取共享商品的服务类
 *
 * Author: lyun
 * Date: 2018/9/21
 * Created by Panxsoft.
 */

namespace App\Services\Repositories\Product;

use App\Http\Requests\Admin\Customer\Product\ShareProductIndexRequest;
use App\Models\Customer\Customer;
use App\Models\Panx\Category;
use App\Models\Panx\Product;
use App\Models\Panx\Sex;
use App\Services\Utils\PanxCollection;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;

class ShareProductRepository
{
    /**
     * @param $virtual_customer_ids
     * @param $customer_category_ids
     * @param $has_asset
     * @param $customer_id
     * @param ShareProductIndexRequest $request
     * @return LengthAwarePaginator
     */
    public function indexShareProducts(
       array $virtual_customer_ids, array $customer_category_ids,
       int $has_asset, int $customer_id,
       ShareProductIndexRequest $request): LengthAwarePaginator
   {
       /** @var LengthAwarePaginator $products */
       $products = (new Product)
           ->filterOnShelf()
           ->filterCustomersOwn($virtual_customer_ids) // 过滤出正常的虚拟供应商
           ->filterCategoryHasAsset($has_asset)   // 过滤商品的类型：化妆品和护肤品
           ->whereIn('category_id', $customer_category_ids) // 过滤客户有的分类
           ->filterCategory($request->category_id) // 过滤前端请求的分类
           ->columnsKeywordOrLike(['title', 'name'], $request->keyword)
           ->filterBrandName($request->brand_name)
           ->orderByDefaultLatest($request->order_column, $request->sort)
           ->with([
               'brand', 'brandSeries', 'cosmeticMaterial',
               'colorThumbImage', 'thumbImage',
               'productTags', 'bodyPositions', 'shareProducts',
               'asset'
           ])
           ->paginate($request->per_page?:15);

       $this->transformProducts($products, $has_asset, $customer_id);

       return $products;
   }

    /**
     * @param Customer $customer
     * @param $language_id
     * @return array|\Illuminate\Http\Response
     */
    public function getBrandsAndGroupCategories(Customer $customer, $language_id): array
    {
        $customer_categories = $customer->categoriesIsShowLatestPriority($language_id);

        $group_brands = $this->groupVirtualBrandsByCategory();

        $group_categories = $this->groupCategoryByCustomType($customer_categories, $group_brands);

        $customer_brands_with_series = $customer->getBrandsWithSeries();

        return compact('group_categories', 'customer_brands_with_series');
    }

    /**
     * @param LengthAwarePaginator $products
     * @param int $has_asset
     *
     * @param int $customer_id
     *
     * @return BaseCollection
     */
    private function transformProducts(LengthAwarePaginator $products, int $has_asset, int $customer_id)
    {
        $products = $products->getCollection();

        $products->transform(function(Product $product) use ($has_asset, $customer_id) {
            $product->customer_ref_count = $this->getCustomerRefCount($product->shareProducts, $customer_id);
            $product->product_type = $has_asset;

            $sex_map = Sex::SEX_MAPS[app()->getLocale()] ?? head(Sex::SEX_MAPS);
            $product->sex_name = $sex_map[$product->sex];

            return $product;
        });

        (new PanxCollection($products))
            ->eachAppend([
                'brand_name', 'brand_series_name', 'cosmetic_material_name',
                'color_thumb_url', 'thumb_url',
                'tag_names', 'body_position_names', 'asset_code'
            ])
            ->makeHidden([
                'brand', 'brandSeries', 'cosmeticMaterial',
                'colorThumbImage', 'thumbImage',
                'productTags', 'bodyPositions', 'shareProducts'
            ]);

        return $products;
    }

    /**
     * @param Collection $share_products
     * @param $customer_id
     * @return int
     */
    private function getCustomerRefCount(Collection $share_products, $customer_id)
    {
        $customer_ref_count = $share_products
            ->where('customer_id', $customer_id)
            ->count();

        return $customer_ref_count;
    }

    /**
     * @return BaseCollection
     */
    private function groupVirtualBrandsByCategory(): BaseCollection
    {
        /** @var Collection $providers */
        $providers = Customer::virtualProviders();
        $virtual_products = (new Product)
            ->filterOnShelf()
            ->filterCustomersOwn($providers->modelKeys()) // 过滤出正常的虚拟供应商
            ->with('brand')
            ->get(['id', 'category_id', 'brand_id']);

        $group_brands_by_category = $virtual_products
            ->groupBy('category_id')
            ->map(function(Collection $products, $category_id) {
                return [
                    'category_id' => $category_id,
                    // 同名品牌需要根据 name 去重
                    'brands'      => $products->pluck('brand')
                        ->unique('name')
                        ->values()
                        ->prepend(['id'=>0, 'name'=>'全部'])
                ];
            })
            ->values();

        return $group_brands_by_category;
    }

    /**
     * @param Collection $customer_categories
     * @param BaseCollection $provider_brands_group_by_category
     *
     * @return Collection
     */
    private function groupCategoryByCustomType(Collection $customer_categories,
                                               BaseCollection $provider_brands_group_by_category)
    {
        $language = app()->getLocale();
        $group_brands = $provider_brands_group_by_category;

        $group_categories = $customer_categories->groupBy('has_asset');

        $group_categories->transform(function(Collection $group_category, int $has_asset) use($language, $group_brands){

            $group_category_ids_by_has_asset = $group_category->pluck('id');

            $group_category->prepend((new Category)->fill(["id" => 0, "name" => "全部",]));

            $group_category->each(function(Category $category) use($group_brands, $group_category_ids_by_has_asset){

                $category->brands = $this->getBrands($group_brands, $category->id, $group_category_ids_by_has_asset);
            });

            $category_custom_types = Category::CUSTOM_TYPE_MAPS[$language] ?? head(Category::CUSTOM_TYPE_MAPS);

            return [
                'custom_type_name' => $category_custom_types[$has_asset],
                'custom_type_id'   => $has_asset,
                'categories'       => $group_category,
            ];
        });

        return $group_categories->values();
    }

    /**
     * @param BaseCollection $brands_group_by_category
     * @param int|null $category_id
     * @param BaseCollection $group_category_ids_by_has_asset
     * @return BaseCollection|null
     */
    private function getBrands(BaseCollection $brands_group_by_category,
                               ?int $category_id,
                               BaseCollection $group_category_ids_by_has_asset): ?BaseCollection
    {
        if ($category_id === 0) {
            return $brands_group_by_category->whereIn('category_id', $group_category_ids_by_has_asset)
                ->pluck('brands')
                ->collapse()
                ->unique('name')
                ->values();
        }

        $group = $brands_group_by_category->where('category_id', $category_id)->first();

        return $group['brands'] ?? collect([['id'=>0, 'name'=>'全部']]);
    }

    private function getProductsByHasAsset(Collection $virtual_products, $has_asset = 0)
    {
        return $virtual_products->filter(function (Product $product) use($has_asset){
               return $has_asset
                   ? Category::hasAsset($product->category_id)
                   : !Category::hasAsset($product->category_id);
        })
            ->pluck('brand')
            ->unique()
            ->values();
    }
}